#include"DatabaseView.h" 

#include<QMenu>
#include<QMimeData>
#include<QMouseEvent>
#include<QTreeWidgetItem>
#include<QUrl>

#include"MetaDataEditor.h"

DatabaseView::DatabaseView(QWidget *parent):QTreeWidget(parent){
	m_root = new QTreeWidgetItem(this, QStringList("All Music"));
	m_root->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
	
	connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotItemExpanded(QTreeWidgetItem*)));
	
	setDragDropMode(QAbstractItemView::DragOnly);
	setSelectionMode(QAbstractItemView::ExtendedSelection);
	setHeaderHidden(true);
}

DatabaseView::~DatabaseView(){
	
}
#include<stdio.h>
void DatabaseView::slotItemExpanded(QTreeWidgetItem *item){
	printf("DatabaseView::slotItemExpanded\n");
	if(item->childCount() > 0)//It's already populated.
		return;
	short unsigned int level = _level(item);
	if(level > 2){
		item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
		return;
	}
	switch(level){
		case 0:
			emit requestPopulate();
			break;
		case 1:
			emit requestPopulate(item->data(0, Qt::DisplayRole).toString());
			break;
		case 2:
			emit requestPopulate(item->parent()->data(0, Qt::DisplayRole).toString(), item->data(0, Qt::DisplayRole).toString());
			break;
	}
}

short unsigned int DatabaseView::_level(QTreeWidgetItem *item)const{
	short unsigned int ret = 0;
	QTreeWidgetItem *counter = item;
	while( (counter = counter->parent()) != 0)
		ret++;
	return ret;
}

void DatabaseView::populate(QList<QString> artists){
	for(int i = 0; i < artists.size(); i++){
		QTreeWidgetItem *item = new QTreeWidgetItem(m_root, QStringList(artists[i]));
		item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
		m_root->addChild(item);
	}
}

void DatabaseView::populate(const QString &artist, QList<QString> albums){
	QTreeWidgetItem *parent = _getItem(artist);
	for(int i = 0; i < albums.size(); i++){
		QTreeWidgetItem *item = new QTreeWidgetItem(parent, QStringList(albums[i]));
		item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
		parent->addChild(item);
	}
}

void DatabaseView::populate(const QString &artist, const QString &album, QList<QString> songs ){
	QTreeWidgetItem *parent = _getItem(artist, album);
	for(int i = 0; i < songs.size(); i++){
		QTreeWidgetItem *item = new QTreeWidgetItem(parent, songs[i].split('\n', QString::SkipEmptyParts));
		item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
		parent->addChild(item);
	}
}

QTreeWidgetItem *DatabaseView::_getItem(const QString &artist, const QString &album)const{
	QTreeWidgetItem *ret = 0;
	for(int i = 0; i < m_root->childCount() && ret == 0; i++)
		if( m_root->child(i)->data(0, Qt::DisplayRole).toString() == artist )
			ret = m_root->child(i);
	
	if(!album.isEmpty()){
		QTreeWidgetItem *parent = ret;
		ret = 0;
		for(int i = 0; i < parent->childCount() && ret == 0; i++)
			if(parent->child(i)->data(0, Qt::DisplayRole).toString() == album)
				ret = parent->child(i);
	}
	
	return ret;
}

bool DatabaseView::rootPopulated()const{
	return m_root->childCount() > 0;
}

bool DatabaseView::artistPopulated(const QString &artist)const{
	QTreeWidgetItem *item = _getItem(artist);
	if(item && item->childCount() > 0)
		return true;
	else
		return false;
}

bool DatabaseView::albumPopulated(const QString &artist, const QString &album)const{
	QTreeWidgetItem *item = _getItem(artist, album);
	if(item && item->childCount() > 0)
		return true;
	else
		return false;
}

void DatabaseView::ensureArtistsEqual(const QList<QString> &artists){
	printf("DatabaseView::ensureArtistsEqual\n");
	_ensureChildrenEqual(m_root, artists);
}

void DatabaseView::ensureAlbumsEqual(const QString &artist, const QList<QString> &albums){
	printf("DatabaseView::ensureAlbumsEqual\n");
	QTreeWidgetItem *parent = _getItem(artist);
	if(!parent){
		printf("!!!CRITICAL!!!: DatabaseView::ensureAlbumsEqual(%s), artist not found.\n", artist.toUtf8().data());
		return;
	}
	
	_ensureChildrenEqual(parent, albums);
}

void DatabaseView::ensureSongsEqual(const QString &artist, const QString &album, const QList<QString> &songs){
	printf("DatabaseView::ensureSongsEqual\n");
	QTreeWidgetItem *parent = _getItem(artist, album);
	if(!parent){
		printf("!!!CRITICAL!!!: DatabaseView::ensureSongsEqual(%s,%s), artist/album not found.\n", artist.toUtf8().data(), album.toUtf8().data());
		return;
	}
	_ensureChildrenEqual(parent, songs, true);
}

void DatabaseView::_ensureChildrenEqual(QTreeWidgetItem *parent, const QList<QString> &data, bool isSongData){
	for(int i = 0; i < data.size(); i++){
		if(parent->child(i) == 0){
			printf("\tAppending %s\n", data[i].toUtf8().data());
			_insertChild(parent, data[i], i, isSongData);
			continue;
		}
	
		QString childData = parent->child(i)->data(0, Qt::DisplayRole).toString();
		if(isSongData){
			childData.append('\n');
			childData.append( parent->child(i)->data(1, Qt::DisplayRole).toString() );
		}
		
		if(childData == data[i]){
			//The hopefully most common case. Don't need to do anything here.
			printf("\t%s exists and positioned correctly.\n", data[i].toUtf8().data());
		}else if(isSongData){//No alphabetic sorting for songs
			printf("\tNew found: %s\n", data[i].split('\n')[0].toUtf8().data());
			_insertChild(parent, data[i], i, isSongData);
		}else if(childData < data[i]){
			//childData no longer exists in DB.
			printf("\tNot found, deleting: %s\n", parent->child(i)->data(0, Qt::DisplayRole).toString().toUtf8().data());
			parent->removeChild( parent->child(i) );
			i--;
			continue;
		}else if(childData > data[i]){
			printf("\tNew found: %s\n", data[i].toUtf8().data());
			//This comes before child
			_insertChild(parent, data[i], i, isSongData);
		}
	}
	
	while( parent->child(data.size()) )
		parent->removeChild(parent->child(data.size()));
}

void DatabaseView::_insertChild(QTreeWidgetItem *parent, const QString &data, int index, bool isSongData){
	QStringList newChildData = isSongData ? data.split('\n', QString::SkipEmptyParts) : QStringList(data);
	QTreeWidgetItem *child = new QTreeWidgetItem(newChildData);
	child->setChildIndicatorPolicy(isSongData ? QTreeWidgetItem::DontShowIndicator : QTreeWidgetItem::ShowIndicator);
	parent->insertChild( index, child );
}

QList<QUrl> DatabaseView::_getSongUrls(QTreeWidgetItem *item)const{
	QList<QUrl> ret;
	short int level = _level(item);
	printf("DatabaseView::_getSongUrls(%lx) at level %d\n", (long unsigned)item, level);
	if(level < 3 && item->childCount() == 0){
		printf("Requesting population at level %d\n", level);
		if(level == 0)
			emit requestPopulate();
		else if(level == 1)
			emit requestPopulate(item->data(0, Qt::DisplayRole).toString());
		else if(level == 2)
			emit requestPopulate(item->parent()->data(0, Qt::DisplayRole).toString(), item->data(0, Qt::DisplayRole).toString());
	}
	printf("Populated.\n");
	if(level == 3)
		ret.append( QUrl(item->data(1, Qt::DisplayRole).toString()) );
	else{
		for(int i = 0; i < item->childCount(); i++)
			ret.append( _getSongUrls(item->child(i)) );
	}
	
	return ret;
}

QList<QString> DatabaseView::_getSongPaths(QTreeWidgetItem *item)const{
	QList<QUrl> data = _getSongUrls(item);
	QList<QString> ret;
	for(int i = 0; i < data.size(); i++)
		ret.push_back( data[i].toString().remove("file://") );
	return ret;
}

QMimeData *DatabaseView::mimeData(const QList<QTreeWidgetItem*> its)const{
	printf("DatabaseView::mimeData:\n");
	QList<QTreeWidgetItem*> items;
	for(int i = 0; i < its.size(); i++)
		items.push_back( its[i] );
	
	//This is to avoid duplicates. Should kinda check for item->parent()->parent() too, but ... Meh.
	for(int i = 0; i < its.size(); i++){
		if(its[i]->parent() && items.contains(its[i]->parent())){
			items.removeAll(its[i]->parent());
		}
	}
	
	QList<QUrl> songPaths;
	for(int i = 0; i < items.size(); i++)
		songPaths.append(_getSongUrls(items[i]));
	
	QMimeData *ret = new QMimeData;
	ret->setUrls(songPaths);
	
	for(int i = 0; i < songPaths.size(); i++)
		printf("\t%s\n", songPaths[i].toString().toUtf8().data());
	
	return ret;
}

QStringList DatabaseView::mimeTypes()const{
	QStringList ret;
	ret.push_back("text/uri-list");
	return ret;
}

void DatabaseView::mousePressEvent(QMouseEvent *event){
	QTreeWidget::mousePressEvent(event);
	if(event->button() == Qt::RightButton && itemAt(event->pos())){
		event->accept();
		QMenu *menu = new QMenu(this);
		if(_level(itemAt(event->pos())) > 0){
			QAction *action = menu->addAction("Edit metadata");
			connect(action, SIGNAL(triggered()), this, SLOT(slotEditMetadata()));
		}
		
		QAction *action = menu->addAction("Add to playlist");
		connect(action, SIGNAL(triggered()), this, SLOT(slotAddToPlaylist()));
		menu->exec(event->globalPos());
	}
}

void DatabaseView::slotEditMetadata(){
	MetaDataEditor::launchEditor(_selectedPaths());
}

void DatabaseView::slotAddToPlaylist(){
	emit addToPlaylist(_selectedPaths());
}

QList<QString> DatabaseView::_selectedPaths()const{
	QList<QString> ret;
	QList<QTreeWidgetItem*> its = selectedItems();
	for(int i = 0; i < its.size(); i++){
		if( its.contains(its[i]->parent()) ){
			its.removeAll(its[i]->parent());
			i--;
		}
	}
	for(int i = 0; i < its.size(); i++)
		ret.append( _getSongPaths(its[i]) );
	return ret;
}

/*QList<QUrl> DatabaseView::_selectedUrls()const{
	QList<QUrl> ret;
	QList<QTreeWidgetItem*> its = selectedItems();
	for(int i = 0; i < its.size(); i++){
		if( its.contains(its[i]->parent()) ){
			its.removeAll(its[i]->parent());
			i--;
		}
	}
	for(int i = 0; i < its.size(); i++)
		ret.append( _getSongUrls(its[i]) );
	return ret;
}*/

//TODO THIS NEVER EVER FUCKING MATCHES A FUCKING THING
void DatabaseView::removeSongWithPath(QString path){
	printf("removeSongWithPath(%s)\n", path.toUtf8().data());
	QList<QTreeWidgetItem*> songs = findItems(path, Qt::MatchRecursive, 1);
	bool verbose = false;
	if(songs.size() > 1){
		printf("Something weird happened in DatabaseView::removeSongWithPath(%s)...\n", path.toUtf8().data());
		verbose = true;
	}else if(songs.size() == 0)
		printf("No matches found :|\n");
	for(int i = 0; i < songs.size(); i++){
		QTreeWidgetItem *parent = songs[i]->parent();
// 		if(verbose)
			printf("\tDeleting: %s\n", songs[i]->data(1, Qt::DisplayRole).toString().toUtf8().data());
		parent->removeChild(songs[i]);
		delete songs[i];
		_deleteIfChildless(parent);
	}
}

void DatabaseView::_deleteIfChildless(QTreeWidgetItem *item)const{
	if(item == m_root)
		return;
	if(item->childCount() > 0)
		return;
	QTreeWidgetItem *parent = item->parent();
	parent->removeChild(item);
	delete item;
	_deleteIfChildless(parent);
}

